# ⚡ Well layered FastAPI app: Cryptids

## Directory structure

- 📁 *web*: The FastAPI web layer;
- 📁 *service*: The business logic layer;
- 📁 *data*: The storage interface layer;
- 📁 *model*: Pydantic model definitions;
- 📁 *fake*: Early hardcoded (*stub*) data - i.e. fake *service+data* layers.
- 📁 *test*
  - 📁 *unit*: Exercise single functions, but don’t cross layer boundaries.
    - 📁 *web*: Web-layer unit tests.
    - 📁 *service*: Service-layer unit tests.
    - 📁 *data*: Data-layer unit tests.
  - 📁 *full*: End-to-end tests. They address the API endpoints in the Web layer.

## Tests

Run from `cryptids/` directory (using config in `pyproject.toml` file):

```bash
# With verbose output:
pytest -v
# Silent, only errors and warnings:
pytest -q
```

Or, run from base repo directory:

```bash
export PYTHONPATH=$PWD/cryptids
pytest -v cryptids/test/unit/service/*.py
pytest -v cryptids/test/unit/data/*.py
pytest -v cryptids/test/unit/web/*.py
pytest -v cryptids/test/full/*.py
```

Run `schemathesis` tests:
```bash
schemathesis run http://localhost:8000/openapi.json --experimental=openapi-3.1
```

## Env vars

| Variable | Meaning |
|----------|---------|
| CRYPTID_SQLITE_DB | Path to a file or ":memory:", used in data layer unit tests. |
| CRYPTID_UNIT_TEST | Used in "service/user.py" to toggle fake data layer in tests. Set in tests, no need to set it manually. |

## Authentication Steps

Here’s a review of that heap of code from the previous sections *(p. 176)*:

- If an endpoint has the dependency `oauth2_dep()` (in *web/user.py*), a form containing username and password fields is generated and sent to the client.

- After the client fills out and submits this form, the username and password (hashed with the same algorithm as those already stored in the local database) are matched against the local database.

- If a match occurs, an access token is generated (in JWT format) and returned.

- This access token is passed back to the web server as an `Authorization` HTTP header in subsequent requests. This JWT token is decoded on the local server to the username and other details. This name does not need to be looked up in the database again.

- The username is authenticated, and the server can do whatever it likes with it.

----
